﻿

#include "ksstr.h"

#pragma warning(push)
#pragma warning( disable : 4290 )


namespace ksstr
{


	bool Key::checkKeyValidName(const std::string& str)
	{

		for(size_t c=0; c<str.length(); c++)
		{
			if( (str[c] >= 'A') && (str[c] <='Z') )
			{
				continue;
			}

			if( (str[c] >= 'a') && (str[c] <='z') )
			{
				continue;
			}

			if( (str[c] >= '0') && (str[c] <='9') )
			{
				continue;
			}

			if( str[c] == '_')
			{
				continue;
			}


			return false;

		}

		return true;
	}

	bool Key::checkValueValidName(const std::string& str) 
	{
		for(size_t c=0; c<str.length(); c++)
		{
			const char  curr = str[c];
			if( (curr == 13) || (curr == 10) ) return false;
		}




		return true;
	}



	Key::Key(const std::string& _key, const std::string& _value) throw ( std::runtime_error)
	{
		m_key = _key;
		m_value = _value;

		if(!checkKeyValidName(m_key))
		{
			m_key = "";
			m_value = "";

			throw std::runtime_error("bad key");
		}

		if(!checkValueValidName(m_value))
		{
			m_key = "";
			m_value = "";

			throw std::runtime_error("bad value");
		}


	}

	Key::Key(const std::string& kv) throw ( std::runtime_error)
	{
		if(kv.empty() )
		{
			m_key = "";
			m_value = "";
			return;
		}

		int separatorPos = -1;
		for(size_t c=0; c<kv.length(); c++)
		{
			if(kv[c]=='=')
			{
				separatorPos = (int)c;
				break;
			}
		}

		if(separatorPos == -1)
		{
			throw std::runtime_error("separator not found ");
		}
 

		m_key = kv.substr( 0, separatorPos );
		m_value = kv.substr(separatorPos+1, kv.length()-separatorPos);

		if(!checkKeyValidName(m_key))
		{
			throw std::runtime_error("bad key name");
		}

		if(!checkValueValidName(m_value))
		{
			throw std::runtime_error("bad value name");
		}



	}



	size_t Keys::Add(const std::string& _key, const std::string& _value) 
		throw(std::runtime_error)
	{



		for(size_t c=0; c<size(); c++)
		{
			if( at(c).m_key == _key )
			{
				throw std::runtime_error("key exists");
			}
		}

		Key _key_item(_key,_value);

		push_back(_key_item);
		return size();
	}

	size_t Keys::searchKeyIndex( const std::string& keyName )
	{

		for(size_t c=0; c<size(); c++)
		{
			if( keyName == at(c).m_key )
			{
				return c;
			}
		}

		return 0-1;
	}

	bool Keys::checkKeyExists(const std::string& keyName) const 
	{

		for(size_t c=0; c<size(); c++)
		{
			if( keyName == at(c).m_key )
			{
				return true;
			}
		}


		return false;
	}

	void Keys::writeToText(std::string& dest) const
	{
		dest = "";
		for(size_t c=0; c<size(); c++)
		{
			dest += at(c).m_key;
			dest += "=";
			dest += at(c).m_value;
			if( c != size()-1 )
			{
				// not last
				dest += "\n";
			}
		}
	}


	void Keys::readFromText(const std::string& argtext) throw(std::runtime_error)
	{
		clear();

		if(argtext.length() <1)
		{
			throw std::runtime_error(" empty text ");
		}




		// remove comments
		std::string text;
		ksstr::preprocessCppComments(text, argtext, 0);

		// split str
		std::vector<std::string> lines;
		lines.reserve(256);
		ksstr::splitLines(lines, text);


		// trim str
		for(size_t c=0; c<lines.size(); c++)
		{
			lines[c] = ksstr::trimCopy( lines[c] );
		}


		// remove empty
		ksstr::removeEmptyLines(lines);



		// read key and value
		//
		//key_values   _key_values;
		{
			std::string _key;
			std::string _value;

			std::string currline;

			// extract key
			for(size_t c=0; c<lines.size(); c++)
			{
				_key = "";
				_value = ""; 
				currline = lines[c];

				size_t eq_pos = 0;
				for(size_t j=0; j<currline.length(); j++)
				{


					if( currline [j] == '=' )
					{
						eq_pos = j;
						break;
					}

					_key.push_back( currline[j] );
				}

				if(eq_pos == 0)
				{
					throw std::runtime_error("bad line");
				}

				// extract value
				for(size_t j=eq_pos+1; j<currline.length(); j++)
				{
					_value.push_back( currline [j] );
				}

				// add
				try
				{

					Key kv(_key, _value);
					push_back( kv  );
				}
				catch (std::runtime_error e)
				{
					throw std::runtime_error(e);
				}



			} // for



		}
		//
		// end (read key and value)


	}


	void Keys::writeToFile(const std::wstring& filename) 
		throw(std::runtime_error)
	{
		std::string temp;
		temp.reserve( size() * 16 );
		writeToText(temp);
		ksstr::saveStrToFileW(temp, filename.c_str() );
	}

	void Keys::readFromFile(const std::wstring& filename) 
		throw(std::runtime_error)
	{
		std::string temp;
		ksstr::loadStrFromFileW(temp, filename.c_str() );
		readFromText(temp);
	}


	const std::string& Keys::getValue(const std::string& keyName) const 
		throw(std::runtime_error)
	{

		for(size_t c=0; c<size(); c++)
		{
			if( at(c).m_key == keyName )
			{
				return at(c).m_value;
			}
		}


		throw std::runtime_error("key not found");
	}


	namespace test
	{
		void do_test_keys()
		{
			Keys keys;

			keys.Add("mykay0","myvalue0");
			keys.Add("mykay1","myvalue1");
			keys.Add("mykay2","myvalue2");
			keys.Add("mykay3","myvalue3");

			std::cout << keys;

			std::string temp;
			keys.writeToText(temp);
			keys.clear();
			keys.readFromText(temp);



			int _stop= 0;
		}
	}


}

 
#pragma warning(pop)
